package com.nulldev.util.web.YouTubeExtractor.metadata;

import static com.nulldev.util.web.YouTubeExtractor.util.YouTubeExtractorUtil.getYTString;
import static com.nulldev.util.web.YouTubeExtractor.util.YouTubeExtractorUtil.hasErrors;

import java.io.InputStream;
import java.time.Duration;

import com.nulldev.util.JVM.JVM;
import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.data.Variables;
import com.nulldev.util.data.Arrays.maps.FastMaps;
import com.nulldev.util.internal.backport.concurrency9.Lists;
import com.nulldev.util.io.IOUtils;
import com.nulldev.util.languages.json.uniapi.UniJsonValue;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.web.HttpClient.HttpClient;
import com.nulldev.util.web.HttpClient.HttpMethod;
import com.nulldev.util.web.HttpClient.HttpResponse;
import com.nulldev.util.web.YouTubeExtractor.YouTubeExtractor;
import com.nulldev.util.web.YouTubeExtractor.YouTubeExtractorConstants;
import com.nulldev.util.web.YouTubeExtractor.util.YTRequestObject;
import com.nulldev.util.web.YouTubeExtractor.util.YouTubeAmountFormatter;

public class UpdatedMetadataExtractor {

	private static final Logger log = LoggerFactory.getLogger();

	public static YouTubeMetadata getUpdatedMetadata(final String videoID) throws Exception {
		return getUpdatedMetadata(videoID, null);
	}

	public static YouTubeMetadata getUpdatedMetadata(final String videoID, final String continuation) throws Exception {
		Variables.requireNonNull(videoID, "videoID");
		if (!YouTubeExtractor.isYouTubeID(videoID))
			return null;
		final UniJsonValue obj = YTRequestObject.makeYTRequestCtx(FastMaps.fixedUniMap(new Object[][]
			{
					{ YTRequestObject.YT_REQUEST_VIDEO_ID, videoID } }));
		final UniJsonValue mainObj = UniJsonValue.object();
		mainObj.add("context", obj);
		mainObj.add("videoId", videoID);
		if (continuation != null && !continuation.isEmpty())
			mainObj.add("continuation", continuation);
		final HttpResponse<InputStream> response = HttpClient.getStream()
				.url("https://www.youtube.com/youtubei/v1/updated_metadata?key=" + YouTubeExtractorConstants.API_KEY + "&prettyPrint=false")
				.timeout(Duration.ofSeconds(15)).header("Accept", "*/*").header("Accept-Language", "en-GB,en-US;q=0.9,en;q=0.8")
				.headers(YouTubeExtractor.makeHeaders()).header("Referer", "https://www.youtube.com/watch?v=" + videoID)
				.header("Content-Type", "application/json").headers(YouTubeExtractor.DEFAULT_COOKIES).create(HttpMethod.POST, mainObj.toString());
		final UniJsonValue uv = UniJsonValue.parse(response.data());
		if (hasErrors(uv)) {
			log.error("Response had errors present! Returning null...");
			return null;
		}
		IOUtils.closeQuietly(response);
		String title = null;
		final UniJsonValue actions = uv.get("actions");
		if (actions == null || actions.isNull()) {
			log.warn("No actions found! Returning null...");
			log.info(uv);
			return null;
		}
		final UniJsonValue _titleObj = actions.arrayGetContains("updateTitleAction");
		if (_titleObj != null && !_titleObj.isNull()) {
			final UniJsonValue titleObj = _titleObj.get("updateTitleAction");
			title = getYTString(titleObj.get("title"));
		}
		long views = -1L;
		final UniJsonValue _viewsObj = actions.arrayGetContains("updateViewershipAction");
		if (_viewsObj != null && !_viewsObj.isNull()) {
			final UniJsonValue viewsObj = _viewsObj.get("updateViewershipAction");
			final UniJsonValue viewCount = viewsObj.get("viewCount").get("videoViewCountRenderer");

			final String str;
			if (viewCount.contains("originalViewCount")) {
				str = viewCount.getString("originalViewCount");
			} else if (viewCount.contains("unlabeledViewCountValue")) {
				final UniJsonValue unlabeledViewCountValue = viewCount.get("unlabeledViewCountValue");
				str = getYTString(unlabeledViewCountValue);
			} else {
				final UniJsonValue extraShortViewCount = viewCount.get("extraShortViewCount");
				str = getYTString(extraShortViewCount);
			}

			views = YouTubeAmountFormatter.format(str);
		}
		/* TODO: Handle updateDescriptionAction */
		final YouTubeMetadata md = new YouTubeMetadata(videoID, title, "author", "authorID", views, -1, -1, -1, -1, false, ArrayUtils.EMPTY_STRING_ARRAY,
				Lists.of());
		md.setPartialMetadata(true);
		return md;
	}

	public static void main(String[] args) throws Exception {
		final YouTubeMetadata ytm = getUpdatedMetadata("jfKfPfyJRdk");
		if (ytm == null) {
			JVM.println("Failed to extract...");
		} else {
			JVM.println("isPartialMetadata: " + ytm.isPartialMetadata());
			JVM.println("Current Title: " + ytm.getTitle());
			JVM.println("Current View Count: " + ytm.getViewCount());
		}
	}
}
